package data

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"digitalhuman/internal/conf"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/gorilla/websocket"
)

type XunFei struct {
	config *conf.Data
}

func NewXunFei(conf *conf.Data) *XunFei {
	xf := &XunFei{
		config: conf,
	}

	return xf
}

/**
 *  WebAPI 接口调用示例 接口文档（必看）：https://www.xfyun.cn/doc/spark/Web.html
 * 错误码链接：https://www.xfyun.cn/doc/spark/%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E.html（code返回错误码时必看）
 * @author iflytek
 */

func (x *XunFei) ReqXunFeiLlm(content string) {
	c := x.config
	d := websocket.Dialer{
		HandshakeTimeout: 5 * time.Second,
	}
	//握手并建立websocket 连接
	conn, resp, err := d.Dial(assembleAuthUrl1(c.XunFei.HostUrl, c.XunFei.ApiKey, c.XunFei.ApiSecret), nil)
	defer conn.Close()

	if err != nil {
		panic(readResp(resp) + err.Error())
		return
	} else if resp.StatusCode != 101 {
		panic(readResp(resp) + err.Error())
	}

	go func() {
		data := genParams1(c.XunFei.Appid, content)
		err = conn.WriteJSON(data)
		if err != nil {
			log.Error(err)
		}
	}()

	var answer = ""
	//获取返回的数据
	for {
		_, msg, err := conn.ReadMessage()
		if err != nil {
			log.Error("read message error:", err)
			break
		}

		var data map[string]interface{}
		err1 := json.Unmarshal(msg, &data)
		if err1 != nil {
			log.Error("Error parsing JSON:", err)
			return
		}
		log.Error(string(msg))
		//解析数据
		payload := data["payload"].(map[string]interface{})
		choices := payload["choices"].(map[string]interface{})
		header := data["header"].(map[string]interface{})
		code := header["code"].(float64)

		if code != 0 {
			log.Error(data["payload"])
			return
		}
		status := choices["status"].(float64)
		// log.Error(status)
		text := choices["text"].([]interface{})
		content := text[0].(map[string]interface{})["content"].(string)
		if status != 2 {
			answer += content
		} else {
			log.Error("收到最终结果")
			answer += content
			usage := payload["usage"].(map[string]interface{})
			temp := usage["text"].(map[string]interface{})
			totalTokens := temp["total_tokens"].(float64)
			log.Error("total_tokens:", totalTokens)
			conn.Close()
			break
		}

	}
	//输出返回结果
	log.Info(answer)

	time.Sleep(1 * time.Second)
}

func (x *XunFei) ReqXunFeiDtsCreate(content, vcn string) (*ResponseCreate, error) {
	u := "https://api-dx.xf-yun.com/v1/private/dts_create"

	// 拼接权限url
	c := x.config
	authUrl := assembleAuthUrlDts(u, c.XunFei.ApiKey, c.XunFei.ApiSecret)

	// 然后开始请求
	postData := genParamsDtsCreate(c.XunFei.Appid, content, vcn)
	//log.Info(postData)

	jsonData, err := json.Marshal(postData)
	if err != nil {
		log.Error("json marshal err :", err)
		return nil, err
	}

	// 创建一个带有超时时间的 HTTP 客户端
	client := &http.Client{
		Timeout: 5 * time.Second, // 设置超时时间为 5 秒
	}

	// 创建 POST 请求
	req, err := http.NewRequest("POST", authUrl, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Error("Error creating request:", err)
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Error("Error sending request:", err)
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应内容
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Error("Error reading response body:", err)
		return nil, err
	}

	var response *ResponseCreate
	err = json.Unmarshal(respBody, &response)
	if err != nil {
		log.Error("Error reading response Unmarshal :", err)
		return nil, err
	}
	// 打印响应内容
	// log.Info("Response Body:", string(respBody))

	return response, nil
}

func (x *XunFei) ReqXunFeiDtsQuery(taskId string) *ResponseQuery {
	u := "https://api-dx.xf-yun.com/v1/private/dts_query"

	// 拼接权限url
	c := x.config
	authUrl := assembleAuthUrlDts(u, c.XunFei.ApiKey, c.XunFei.ApiSecret)

	// 然后开始请求
	postData := map[string]interface{}{
		"header": map[string]interface{}{
			"app_id":  c.XunFei.Appid,
			"task_id": taskId,
		},
	}

	jsonData, err := json.Marshal(postData)
	if err != nil {
		log.Error("json marshal err :", err)
		return nil
	}

	// 创建一个带有超时时间的 HTTP 客户端
	client := &http.Client{
		Timeout: 10 * time.Second, // 设置超时时间为 10 秒
	}

	// 创建 POST 请求
	req, err := http.NewRequest("POST", authUrl, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Error("Error creating request:", err)
		return nil
	}
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Error("Error sending request:", err)
		return nil
	}
	defer resp.Body.Close()

	// 读取响应内容
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Error("Error reading response body:", err)
		return nil
	}

	var response *ResponseQuery
	err = json.Unmarshal(respBody, &response)
	if err != nil {
		log.Error("Error reading response Unmarshal :", err)
		return nil
	}
	//log.Error(resp.StatusCode)
	// 打印响应内容
	// log.Info("Xf Query Response Body:", string(respBody))
	b, err := base64.StdEncoding.DecodeString(response.Payload.Audio.Audio)
	if err != nil {
		log.Error(err)
		return nil
	}
	response.Payload.Audio.Audio = string(b)

	return response
}

// ------------ 所需要的函数 --------
// 生成参数
func genParams1(appid, question string) map[string]interface{} { // 根据实际情况修改返回的数据结构和字段名
	messages := []Message{
		{Role: "user", Content: question},
	}

	data := map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
		"header": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
			"app_id": appid, // 根据实际情况修改返回的数据结构和字段名
		},
		"parameter": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
			"chat": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
				"domain":      "general",    // 根据实际情况修改返回的数据结构和字段名
				"temperature": float64(0.8), // 根据实际情况修改返回的数据结构和字段名
				"top_k":       int64(6),     // 根据实际情况修改返回的数据结构和字段名
				"max_tokens":  int64(2048),  // 根据实际情况修改返回的数据结构和字段名
				"auditing":    "default",    // 根据实际情况修改返回的数据结构和字段名
			},
		},
		"payload": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
			"message": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
				"text": messages, // 根据实际情况修改返回的数据结构和字段名
			},
		},
	}
	return data // 根据实际情况修改返回的数据结构和字段名
}

// 创建鉴权url  apikey 即 hmac username
func assembleAuthUrl1(hosturl string, apiKey, apiSecret string) string {
	ul, err := url.Parse(hosturl)
	if err != nil {
		log.Error(err)
	}
	//签名时间
	date := time.Now().UTC().Format(time.RFC1123)
	//date = "Tue, 28 May 2019 09:10:42 MST"
	//参与签名的字段 host ,date, request-line
	signString := []string{"host: " + ul.Host, "date: " + date, "GET " + ul.Path + " HTTP/1.1"}
	//拼接签名字符串
	sgin := strings.Join(signString, "\n")
	// log.Error(sgin)
	//签名结果
	sha := HmacWithShaTobase64("hmac-sha256", sgin, apiSecret)
	// log.Error(sha)
	//构建请求参数 此时不需要urlencoding
	authUrl := fmt.Sprintf("hmac username=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey,
		"hmac-sha256", "host date request-line", sha)
	//将请求参数使用base64编码
	authorization := base64.StdEncoding.EncodeToString([]byte(authUrl))

	v := url.Values{}
	v.Add("host", ul.Host)
	v.Add("date", date)
	v.Add("authorization", authorization)
	//将编码后的字符串url encode后添加到url后面
	callurl := hosturl + "?" + v.Encode()
	return callurl
}

func HmacWithShaTobase64(algorithm, data, key string) string {
	mac := hmac.New(sha256.New, []byte(key))
	mac.Write([]byte(data))
	encodeData := mac.Sum(nil)
	return base64.StdEncoding.EncodeToString(encodeData)
}

func readResp(resp *http.Response) string {
	if resp == nil {
		return ""
	}
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("code=%d,body=%s", resp.StatusCode, string(b))
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// 生成参数
func genParamsDtsCreate(appid, question, vcn string) map[string]interface{} {
	data := map[string]interface{}{
		"header": map[string]interface{}{
			"app_id": appid,
		},
		"parameter": map[string]interface{}{
			"dts": map[string]interface{}{
				"vcn":      vcn,
				"language": "zh",
				"speed":    50,
				"volume":   50,
				"pitch":    50,
				"rhy":      1,
				"audio": map[string]interface{}{
					"encoding":    "lame",
					"sample_rate": 16000,
				},
				"pybuf": map[string]interface{}{
					"encoding": "utf8",
					"compress": "raw",
					"format":   "plain",
				},
			},
		},
		"payload": map[string]interface{}{ // 根据实际情况修改返回的数据结构和字段名
			"text": map[string]interface{}{
				"encoding": "utf8",
				"compress": "raw",
				"format":   "plain",
				"text":     base64.StdEncoding.EncodeToString([]byte(question)),
			},
		},
	}
	return data // 根据实际情况修改返回的数据结构和字段名
}

// 创建鉴权url  apikey 即 hmac username
func assembleAuthUrlDts(hosturl string, apiKey, apiSecret string) string {
	ul, err := url.Parse(hosturl)
	if err != nil {
		log.Error(err)
	}
	//签名时间
	date := time.Now().UTC().Format(time.RFC1123)
	//参与签名的字段 host ,date, request-line
	signString := []string{"host: " + ul.Host, "date: " + date, "POST " + ul.Path + " HTTP/1.1"}
	//拼接签名字符串
	sgin := strings.Join(signString, "\n")
	// log.Error(sgin)
	//签名结果
	sha := HmacWithShaTobase64("hmac-sha256", sgin, apiSecret)
	// log.Error(sha)
	//构建请求参数 此时不需要urlencoding
	authUrl := fmt.Sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey,
		"hmac-sha256", "host date request-line", sha)
	//将请求参数使用base64编码
	authorization := base64.StdEncoding.EncodeToString([]byte(authUrl))

	v := url.Values{}
	v.Add("host", ul.Host)
	v.Add("date", date)
	v.Add("authorization", authorization)
	//将编码后的字符串url encode后添加到url后面
	callurl := hosturl + "?" + v.Encode()
	return callurl
}

// 定义要解析的 JSON 结构体
type ResponseCreate struct {
	Header  HeaderData  `json:"header"`
	Payload interface{} `json:"payload"` // 使用interface{}表示任意类型
}

type ResponseQuery struct {
	Header  HeaderData  `json:"header"`
	Payload PayloadData `json:"payload"`
}

type HeaderData struct {
	Code       int    `json:"code"`
	Message    string `json:"message"`
	Sid        string `json:"sid"`
	TaskID     string `json:"task_id"`
	TaskStatus string `json:"task_status"` // 任务状态: 1-任务创建成功 2-任务派发失败 4-结果处理中 5-结果处理完成（包含成功/失败）
}

const TaskStatusCompleted = "5"

type PayloadData struct {
	Audio AudioData `json:"audio"`
	Pybuf PybufData `json:"pybuf"`
}

type AudioData struct {
	Audio      string `json:"audio"`
	BitDepth   string `json:"bit_depth"`
	Channels   string `json:"channels"`
	Encoding   string `json:"encoding"`
	SampleRate string `json:"sample_rate"`
}

type PybufData struct {
	Compress string `json:"compress"`
	Encoding string `json:"encoding"`
	Format   string `json:"format"`
	Text     string `json:"text"`
}
